﻿using System;
using System.Linq;
using TinyEngine.Core.Entities.Parsers;
using TinyEngine.Core.Asset;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using TinyEngine.Core.Services;
using TinyEngine.Core.Renderer;
using TinyEngine.Core.Entities;
using System.Collections.Generic;
using TinyEngine.Core;
namespace TinyEngine.Entities
{
    [TinyEngine.Core.Attributes.EntityParser(typeof(AnimatedSpriteParser))]
    public class AnimatedSpriteEntity : SpriteEntity
    {
        public AnimatedSpriteEntity()
        {
            AnimationLibrary = new AnimationLibrary();
        }

        SpriteAnimation currentAnimation = null;
        public SpriteAnimation CurrentAnimation 
        {
            get { return currentAnimation; }
            private set
            {
                currentAnimation = value;
                PositionChanged();
            }
        }

        public override void PositionChanged()
        {
            if(CurrentAnimation!=null )
            {
                var frame = currentAnimation.CurrentFrame;
                if (frame == null)
                    frame = currentAnimation.Frames[0];
                    
                
                int halfWidth = frame.SourceRectangle.Width/2;
                int halfHeight = frame.SourceRectangle.Height/2;
                this.SetBounds(new Rectangle(
                    (int)Position.X - halfWidth,
                    (int)Position.Y - halfHeight,
                    frame.SourceRectangle.Width,
                    frame.SourceRectangle.Height));
            }

        }

        public override void Register(Core.Scene.TinyScene owner)
        {
            base.Register(owner);

            if (!string.IsNullOrEmpty(this.AnimationLibrary.DefaultAnimation))
            {
                this.PlayAnimation(this.AnimationLibrary.DefaultAnimation);
            }
        }

        public override void CopyTo(object item)
        {
            base.CopyTo(item);
            var an = item as AnimatedSpriteEntity;
            an.AnimationLibrary.DefaultAnimation = this.AnimationLibrary.DefaultAnimation;
            foreach (var animation in this.AnimationLibrary.Animations)
            {
                var newAn = new SpriteAnimation()
                {
                    AssetName = animation.AssetName,
                    Duration = animation.Duration,
                    Loop = animation.Loop,
                    Name = animation.Name
                };
                foreach (var fr in animation.Frames)
                {
                    var newFr = new SpriteFrame()
                    {
                        SourceRectangle = fr.SourceRectangle
                    };
                    newAn.Frames.Add(newFr);
                }
                an.AnimationLibrary.Animations.Add(newAn);
            }
        }
        public AnimationLibrary AnimationLibrary { get; private set; }

        public void PlayAnimation(string name)
        {
            CurrentAnimation = AnimationLibrary.Animations.SingleOrDefault(a => a.Name == name);
            CurrentAnimation.Reset();            
        }
        
        public override void Update(float elapsed)
        {
            if (CurrentAnimation != null)
            {
                CurrentAnimation.Update(elapsed);
            }
            base.Update(elapsed);
        }

        public override void Draw(float elapsed)
        {
            //base.Draw(elapsed);

            var renderer = TinyEngine.Core.Services.ServiceManager.GetService<SpriteBatchService>();
            internalOffset = new Vector2(BoundingRectangle.Width / 2, BoundingRectangle.Height / 2);
            var origin = internalOffset;
            origin += this.Origin;
            if (CurrentAnimation == null)
                return;


            var frame = CurrentAnimation.CurrentFrame;
            if (frame == null)
                return;
            var sprite = TinyEngine.Core.Services.ServiceManager.GetService<AssetLibrary>().GetSprite(CurrentAnimation.AssetName).Asset;
            var src = frame.SourceRectangle;
            
            renderer.Batch.Draw(
                            sprite,
                            this.Position.ToVector2(),
                            src,
                            this.Tint,
                            0,
                            origin,
                            1,
                            GetSpriteEffects(),
                            this.Position.Z
                            );

        }

    }

    public class AnimationLibrary
    {
        public AnimationLibrary()
        {
            Animations = new List<SpriteAnimation>();
        }
        public string DefaultAnimation { get; set; }

        public List<SpriteAnimation> Animations { get; set; }
    }

    public class SpriteAnimation
    {
        public string Name { get; set; }
        public string AssetName { get; set; }
        
        public SpriteAnimation()
        {
            Frames = new List<SpriteFrame>();
        }
        public bool Loop { get; set; }
        public TimeSpan Duration { get; set; }
        public List<SpriteFrame> Frames { get; set; }
        public bool IsRunning { get; set; }
        public SpriteFrame CurrentFrame { get; private set; }
        float timer;
        internal void Update(float elapsed)
        {
            if (CurrentFrame == null && Frames.Count > 0)
                CurrentFrame = Frames[0];

            if (timer <= Duration.TotalSeconds)
            {
                timer += elapsed;
                if (timer == 0 || Duration.TotalSeconds == 0)
                    CurrentFrame = Frames[0];
                else
                {
                    var a = timer / Duration.TotalSeconds;
                    var frame = (int)Math.Round(((double)Frames.Count - 1) * a);
                    CurrentFrame = Frames[frame];
                }
            }
            else
            {
                if (Loop)
                {
                    timer = 0;
                }
                else
                    IsRunning = false;
            }
        }

        internal void Reset()
        {
            timer = 0;
            Update(0);
            IsRunning = true;
        }
    }

    public class SpriteFrame
    {
        public Rectangle SourceRectangle { get; set; }
    }

    public class Storyboard
    {
        public Storyboard()
        {
        }

        public string Name { get; set; }
        
        public TimeSpan Duration { get; set; }

        public List<Timeline> Children { get; set; }

    }
    public class Timeline 
    {
        public Timeline()
        {
        }


    }
}
